Skip to content

Laurel-to-Core translator expansion with grammar improvements#4

Draft
fabiomadge wants to merge 24 commits intokeyboardDrummer:mutableFieldsfrom
fabiomadge:feat/laurel-to-core
Draft

Laurel-to-Core translator expansion with grammar improvements#4
fabiomadge wants to merge 24 commits intokeyboardDrummer:mutableFieldsfrom
fabiomadge:feat/laurel-to-core

Conversation

@fabiomadge
Copy link
Copy Markdown

@fabiomadge fabiomadge commented Jan 23, 2026

Translator:

  • While loops with invariants
  • Quantifiers (forall/exists) with constrained type support
  • Constrained types with boundary checks
  • Arrays (indexing, length, parameter expansion)
  • Sequence operations (Seq.Contains, Seq.Take, Seq.Drop)
  • Proper error handling (Except String instead of panic!)

Grammar:

  • Spacing/indentation for readable output
  • New operators: divT, modT, implies
  • Multiple requires/ensures/invariant clauses

CLI:

  • laurelParse, laurelAnalyze, laurelToCore, laurelPrint commands

Tests:

  • While loops, quantifiers, arrays, sequences, operators

- Add binary operators: sub (-), mul (*), div (/), mod (%)
- Add logical operators: and (&&), or (||)
- Add unary operators: not (!), neg (-)
- Use spaces around && and || operators
- Fix DDM parser to always treat // as line comment (regardless of token table)

The parser fix allows / to be used as a token without breaking // comments.
- Add while loop syntax to grammar with invariant clauses
- Add parser for while loops (combines multiple invariants with &&)
- Add While case to LaurelToCoreTranslator
- Add leftassoc to arithmetic/logical operators (fixes a * b / c parsing)
- Create T4_WhileBasic.lean test
- Change Procedure.precondition to preconditions : List StmtExpr
- Change Body.Opaque/Abstract postcondition to postconditions : List StmtExpr
- Update grammar: requires/ensures now use Seq instead of Option
- Update parser to collect list of requires/ensures clauses
- Update translator to generate indexed labels (proc_pre_0, proc_post_0, etc.)
- Update LaurelFormat, LaurelEval for list-based contracts
- Update canBeBoogieFunction to check preconditions.isEmpty
- Add constrainedType grammar rule and parser
- Add topLevelConstrainedType to TopLevel
- Build ConstrainedTypeMap from program type definitions
- Resolve constrained types to base types in parameter translation
- Generate constraint checks as preconditions for input parameters
- Generate constraint checks as postconditions for output parameters
- Use resolved types in type environment for expression translation
- Create T10_ConstrainedTypes.lean test
- Thread ctMap through translateStmt
- Resolve constrained types to base types for locals
- Generate assertion after init for constrained type locals
- Thread ctMap through translateExpr and lookupType
- Generate constraint assertion after assignment to constrained type variable
- Handle StaticCall specially in Assign case
- Generate call statement instead of function application
- genConstraintAssert: generates constraint assertion for a variable
- defaultExprForType: generates default value for a type
- isHeapFunction: checks if function is heapRead/heapStore
- Grammar: forallExpr, existsExpr with (name: type) => body syntax
- Parser: translate to Laurel.Forall/Exists AST nodes
- Translator: varCloseByName helper, translate to Core quant expressions
- Test: T5_Quantifiers.lean
- forall(x: nat) => body becomes forall x. (x >= 0) ==> body
- exists(x: nat) => body becomes exists x. (x >= 0) && body
- Made translateExpr partial to allow recursive constraint translation
- Add TranslatedConstraintMap with pre-translated Core constraint expressions
- Add translateSimpleExpr for constraint expressions (no quantifiers)
- Build tcMap upfront in translate(), pass through all functions
- Quantifiers use pre-translated constraints, avoiding recursive call on external data
- Restore termination proof for translateExpr
- Explicit cases for Forall/Exists with clear error message
- Better error messages for unsupported operators
Reduces duplication between translateExpr and translateSimpleExpr
- Array type translates to Map int elemType
- Array.Get uses select operation (Core infers types)
- Array.Length uses name#len free variable
- expandArrayParam expands array params to (arr, arr#len) pairs
- Fixed CoreIdent visibility: use unres for operations, matching factory convention
- Sequences represented as (arr, start, end) bounds
- Seq.Contains translates to existential: exists i :: start <= i < end && arr[i] == elem
- Seq.Take adjusts end bound
- Seq.Drop adjusts start bound
- No new axioms needed - direct translation to quantifiers
- Fixed identifier matching for guillemet-escaped names («Seq.Contains» etc)
- Add Forall and Exists cases to isPureExpr so pure functions with
  quantifiers can be translated as Core functions (fixes non-termination)
- Map 'Map' type to SMT 'Array' type in both lMonoTyToSMTString and
  encodeType

Note: There's a remaining issue with user-defined functions taking Map
arguments when called in while loop invariants - the UF key mismatch
between definition and call sites needs further investigation.
…lation

This adds a FunctionTypeMap that maps function names to their types,
built from procedures that can be translated as functions. When
translating a StaticCall, we look up the function type and attach it
to the .op expression.

This is necessary for the SMT encoder to correctly encode user-defined
function calls, as it needs the type information to create the correct
uninterpreted function signatures.

Note: There is still an issue where the type annotation is lost during
evaluation. The type is present in the translated Core program but
missing in the VCs. This needs further investigation.
Grammar:
- Add spacing around operators for readable output
- Add divT, modT (truncating division) and implies operators
- Use NewlineSepBy + indent() for block formatting
- Add newline prefixes for requires/ensures/invariant clauses
- Fix call precedence for proper parsing

Translator:
- Replace panic! with Except String for proper error handling
- Add expandArrayArgs and injectQuantifierConstraint helpers
- Add normalizeCallee for «» quoted identifiers
- Validate array types in Seq.From
- Support multiple invariants (combined with &&)

CLI:
- Add laurelParse, laurelAnalyze, laurelToCore, laurelPrint commands

Tests:
- Add testTruncatingDiv, testUnary, implies tests
- Add multiContract for multiple requires/ensures
@fabiomadge fabiomadge changed the title Laurel grammar formatting and CLI commands Laurel-to-Core translator expansion with grammar improvements Jan 23, 2026
keyboardDrummer added a commit that referenced this pull request Feb 13, 2026
### Changes
- Add a Python script in `Tools` that enables automatically updating the
results of `#guard_msg`
- Update formatting of applications in Core. A good way to see how the
formatting has changed is to look at the updated tests in this PR.

Before:
```
while (((~Int.Lt i) n)) (some ((~Int.Sub n) i)) (some ((~Bool.And ((~Int.Le i) n)) (((~Int.Div ((~Int.Mul i) ((~Int.Sub i) #1))) #2) == sum))) {sum := ((~Int.Add sum) i)
 i := ((~Int.Add i) #1)}
```
After:
```
  while
    (~Int.Lt i n)
    (some (~Int.Sub n i))
    (some (~Bool.And (~Int.Le i n) ((~Int.Div (~Int.Mul i (~Int.Sub i #1)) #2) == sum)))
  {
    sum := (~Int.Add sum i)
    i := (~Int.Add i #1)
  }
```


Applications in expressions require fewer parenthesis are are shown in a
tree like fashion when they do not fit on a line:

Before
```
/-- info: Annotated expression:
((((~List$Elim : (arrow (List (Tup int string)) (arrow int (arrow (arrow (Tup int string) (arrow (List (Tup int string)) (arrow int int))) int)))) (((~Cons : (arrow (Tup int string) (arrow (List (Tup int string)) (List (Tup int string))))) (((~Prod : (arrow int (arrow string (Tup int string)))) #3) #a)) (((~Cons : (arrow (Tup int string) (arrow (List (Tup int string)) (List (Tup int string))))) (((~Prod : (arrow int (arrow string (Tup int string)))) #4) #b)) (~Nil : (List (Tup int string)))))) #0) (λ (λ (λ (((~Int.Add : (arrow int (arrow int int))) (((~Tup$Elim : (arrow (Tup int string) (arrow (arrow int (arrow string int)) int))) %2) (λ (λ %1)))) ((((~List$Elim : (arrow (List (Tup int string)) (arrow int (arrow (arrow (Tup int string) (arrow (List (Tup int string)) (arrow int int))) int)))) %1) #1) (λ (λ (λ (((~Tup$Elim : (arrow (Tup int string) (arrow (arrow int (arrow string int)) int))) %2) (λ (λ %1))))))))))))
```
After
```
/--
info: Annotated expression:
((~List$Elim : (arrow (List (Tup int string)) (arrow int (arrow (arrow (Tup int string) (arrow (List (Tup int string)) (arrow int int))) int))))
 ((~Cons : (arrow (Tup int string) (arrow (List (Tup int string)) (List (Tup int string)))))
  ((~Prod : (arrow int (arrow string (Tup int string)))) #3 #a)
  ((~Cons : (arrow (Tup int string) (arrow (List (Tup int string)) (List (Tup int string)))))
   ((~Prod : (arrow int (arrow string (Tup int string)))) #4 #b)
   (~Nil : (List (Tup int string)))))
 #0
 (λ (λ (λ ((~Int.Add : (arrow int (arrow int int)))
     ((~Tup$Elim : (arrow (Tup int string) (arrow (arrow int (arrow string int)) int))) %2 (λ (λ %1)))
     ((~List$Elim : (arrow (List (Tup int string)) (arrow int (arrow (arrow (Tup int string) (arrow (List (Tup int string)) (arrow int int))) int))))
      %1
      #1
      (λ (λ (λ ((~Tup$Elim : (arrow (Tup int string) (arrow (arrow int (arrow string int)) int)))
          %2
          (λ (λ %1))))))))))))
```

### Testing
Updated tests

---------

Co-authored-by: Andrew Wells <130512013+andrewmwells-amazon@users.noreply.github.com>
@github-actions github-actions Bot added the Git conflicts PR has merge conflicts with the base branch label Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Git conflicts PR has merge conflicts with the base branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants